package com.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bean.ApiCookBook;
import com.bean.ApiInfo;
import com.bean.LoginCreds;
import com.bean.ZjMusic;
import com.bean.base.DictItemInfo;
import com.bean.other.MetaInfo;
import com.bean.other.RedirectInfo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mapper.ApiInfoMapper;
import com.mapper.DictMapper;
import com.mapper.LoginCredsMapper;
import com.mapper.ZjMusicMapper;
import com.mapper.repository.ApiInfoRepository;
import com.mapper.repository.LoginCredsRepository;
import com.service.impl.ApiInfoService;
import com.service.impl.LoginCredsService;
import com.utils.ValidUtil;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;

import javax.net.ssl.SSLException;
import java.time.LocalDateTime;
import java.util.*;

@Service
@Slf4j
public class ApiInfoServiceImpl implements ApiInfoService {

    @Autowired
    private ApiInfoRepository apiInfoRepository;

    @Autowired
    private ApiInfoMapper apiInfoMapper;

    @Override
    public String insert(ApiInfo apiInfo) {
        apiInfo.setId(UUID.randomUUID().toString());
        apiInfo.setCreatetime(LocalDateTime.now());
        apiInfoRepository.save(apiInfo);
        return "新增成功";
    }

    @Override
    public String update(ApiInfo apiInfo) {
        apiInfo.setUpdatetime(LocalDateTime.now());
        apiInfoRepository.save(apiInfo);
        return "更新成功";
    }

    @Override
    public String delete(ApiInfo apiInfo) {
        apiInfoRepository.delete(apiInfo);
        return "删除成功";
    }

    @Override
    public PageInfo<ApiInfo> select(ApiInfo apiInfo, MetaInfo metaInfo) {
        //PageHelper.startPage(metaInfo.getPage(),metaInfo.getSize());
        PageHelper.startPage(metaInfo.getPage(),metaInfo.getSize(),"createtime");
        List<ApiInfo> list=apiInfoMapper.selectLike(apiInfo);
        PageInfo<ApiInfo> pageInfo=new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public ApiInfo get(String id) {
        Optional<ApiInfo> optional=apiInfoRepository.findById(id);
        if(optional.isPresent()){
            return optional.get();
        }
        return null;
    }


    @Autowired
    private WebClient webClient;

    @Autowired
    private WebClient.Builder webClientBuilder;

    @Autowired
    private DictMapper dictMapper;

    @Override
    public JSONObject ApiGetGxdz() {
        JSONObject apiResult =null;
        DictItemInfo dictItemInfo=dictMapper.getDictItemForApi("ApiUrl","Gxdz");
        if(dictItemInfo!=null){
            String url=dictItemInfo.getValue();
            apiResult=  webClientBuilderGet(url);
            //log.info(apiResult.toJSONString());
            apiResult.put("message","数据返回成功！");
            apiResult.put("code",200);
        }else{
            apiResult=new JSONObject();
            apiResult.put("code",200);
            apiResult.put("message","接口错误！");
        }
        return apiResult;
    }

    //IP定位
    @Override
    public JSONObject ApiGetIpdw(String ip) {
        JSONObject apiResult =null;
        DictItemInfo dictItemInfo=dictMapper.getDictItemForApi("ApiUrl","Ipdw");
        if(dictItemInfo!=null){
            String url=dictItemInfo.getValue();
            if(ip!=null&& ValidUtil.isValidIpv4(ip)){
                url=url+"&ip="+ip;
            }
            log.info(url);
            apiResult=  webClientBuilderGet(url);
            //log.info(apiResult.toJSONString());
            apiResult.put("message","数据返回成功！");
            apiResult.put("code",200);
        }else{
            apiResult=new JSONObject();
            apiResult.put("code",200);
            apiResult.put("message","接口错误！");
        }
        return apiResult;
    }

    //IP定位
    @Override
    public JSONObject ApiGetIpdw2(String ip) {
        JSONObject apiResult =null;
        DictItemInfo dictItemInfo=dictMapper.getDictItemForApi("ApiUrl","Ipdw2");
        if(dictItemInfo!=null){
            String url=dictItemInfo.getValue();
            if(ip!=null&& ValidUtil.isValidIpv4(ip)&&!ip.equals("127.0.0.1")){
                url=url+"&ip="+ip;
            }
            log.info(url);
            try {
                apiResult=  webClientBuilderGet(url);
            }catch (Exception e){
                log.info(e.getMessage());
            }
            if(apiResult == null){
                apiResult = new JSONObject();
                JSONObject ipdw = ApiGetIpdw(ip);
                JSONObject result = ipdw.getJSONObject("result");
                if(result!=null){
                    JSONObject adinfo = result.getJSONObject("ad_info");
                    JSONObject info = new JSONObject();
                    info.put("city",adinfo.getString("city"));
                    apiResult.put("info",info);
                }else{
                    JSONObject info = new JSONObject();
                    info.put("city","太原市");
                    apiResult.put("info",info);
                }
            }else{
                String message =apiResult.getString("message");
                if(message != null){
                    if(message.equals("Page Not Found")){
                        JSONObject ipdw = ApiGetIpdw(ip);
                        JSONObject result = ipdw.getJSONObject("result");
                        if(result!=null){
                            JSONObject adinfo = result.getJSONObject("ad_info");
                            JSONObject info = new JSONObject();
                            info.put("city",adinfo.getString("city"));
                            apiResult.put("info",info);
                        }else{
                            JSONObject info = new JSONObject();
                            info.put("city","太原市");
                            apiResult.put("info",info);
                        }
                    }
                }

            }

            //log.info(apiResult.toJSONString());
            apiResult.put("message","数据返回成功！");
            apiResult.put("code",200);
        }else{
            apiResult=new JSONObject();
            apiResult.put("code",200);
            apiResult.put("message","接口错误！");
        }
        return apiResult;
    }

    //实时天气
    @Override
    public JSONObject ApiGetSstq(String location) {
        JSONObject apiResult =null;
        DictItemInfo dictItemInfo=dictMapper.getDictItemForApi("ApiUrl","Sstq");
        if(dictItemInfo!=null){
            String url=dictItemInfo.getValue();
            if(location!=null){
                url=url+"&location="+location;
            }
            log.info(url);
            apiResult=  webClientBuilderGet(url);
            //log.info(apiResult.toJSONString());
            apiResult.put("message","数据返回成功！");
            apiResult.put("code",200);
        }else{
            apiResult=new JSONObject();
            apiResult.put("code",200);
            apiResult.put("message","接口错误！");
        }
        return apiResult;
    }

    //获取菜谱
    @Override
    public List<ApiCookBook> cp(String keyword) {
        JSONObject apiResult =null;
        DictItemInfo dictItemInfo=dictMapper.getDictItemForApi("ApiUrl","cp");
        if(dictItemInfo!=null){
            String url=dictItemInfo.getValue();
            if(keyword!=null){
                url=String.format(url,keyword);
            }
            log.info(url);
            apiResult=  webClientBuilderGet(url);
            if(apiResult.getString("msg").equals("查询成功")){
                ApiCookBook [] apiCookBooks= (ApiCookBook[]) apiResult.getJSONObject("result").getJSONObject("result").getJSONArray("list").toArray();
                return Arrays.asList(apiCookBooks);
            }

        }else{
            return null;
        }
        return null;
    }


    @Autowired
    private ZjMusicMapper zjMusicMapper;

    public JSONObject getSjMusic(){
        JSONObject apiResult = new JSONObject();
        ZjMusic zjMusic = zjMusicMapper.randomMusic();
        apiResult.put("data",zjMusic);
        return apiResult;
    }

    //网易云随机音乐
    @Override
    public JSONObject sjmusic(String type) {
        JSONObject apiResult =null;
        DictItemInfo dictItemInfo=dictMapper.getDictItemForApi("ApiUrl","sjmusic");
        if(dictItemInfo!=null){
            String url=dictItemInfo.getValue();
            log.info(url);
            url = String .format(url,type);
            boolean flag = false;
            int i =0;
            while(!flag){
                i++;

                String result=  webClientBuilderGets(url);
                if(i == 5 || result == null){//302 循环5次后，请求本地的随机音乐,或者返回的结果为null 的时候，就从本地选择音乐
                    apiResult = getSjMusic();
                    apiResult.put("flag","已保存");
                    flag = true;
                }else{
                    log.info("随机音乐请求结果："+result);
                    try {
                        //返回 302重定向，返回的是xml，xml不能转换为json,因此会继续调用
                        apiResult = JSONObject.parseObject(result);
                        apiResult.put("flag","未保存");
                        flag = true;
                    }catch (Exception ex){
                        log.info("随机音乐请求发生错误");
                        log.error(ex.getMessage());
                    }
                }

            }
            //log.info(apiResult.toJSONString());
            apiResult.put("message","数据返回成功！");
            apiResult.put("code",200);
        }else{
            apiResult=new JSONObject();
            apiResult.put("code",200);
            apiResult.put("message","接口错误！");
        }
        return apiResult;
    }

    //Get请求  同步获取
    public JSONObject webClientBuilderGet(String url){
        WebClient webClient=webClientBuilder.baseUrl(url).build();
        JSONObject jsonObject= webClient
                .get()    //发送Get请求
                .retrieve()//检索
                .bodyToMono(JSONObject.class)
                .log()  //日志打印
                .block();//阻塞  同步获取结果
        return jsonObject;
    }


    public JSONObject httpClientGets(String url){


        return null;
    }




    public String webClientBuilderGets(String url) {
        try {
            SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
            HttpClient httpClient = HttpClient.create().secure(t->t.sslContext(sslContext));
            //绕过ssl证书                              禁用重定向   禁用了重定向后，居然显示SSl问题
            //WebClient webClient=webClientBuilder.baseUrl(url).clientConnector(new ReactorClientHttpConnector(httpClient.create().followRedirect(false))).build();
            WebClient webClient=webClientBuilder.baseUrl(url).clientConnector(new ReactorClientHttpConnector(httpClient)).build();

            String result= webClient
                    .get()    //发送Get请求
                    //.header(HttpHeaders.ACCEPT, "json/mp3")
                    .retrieve()//检索  自动会重定向
                    /*.onStatus(HttpStatus::is3xxRedirection, response -> {
                        String location = response.headers().header(HttpHeaders.LOCATION).get(0);
                        System.out.println("重定向的地址为："+location);
                        // 手动处理重定向

                        try {
                            JSONObject result = webClientBuilderGets(location);
                            return Mono.just(result); // 返回 Mono<JSONObject>
                        } catch (Exception e) {
                            return Mono.error(e); // 如果发生错误，返回 Mono<Throwable>
                        }
                    })*/
                    .bodyToMono(String.class)
                    .log()  //日志打印
                    .block();//阻塞  同步获取结果
            return result;
        }catch (Exception e){
            //e.printStackTrace();
            log.error("随机音乐请求失败:"+e.getMessage());
        }
        return null;


    }


    public String webClientBuilderGets2(String url) {
        String result = null;
        try {
            SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
            HttpClient httpClient = HttpClient.create().secure(t->t.sslContext(sslContext));
            //绕过ssl证书                              禁用重定向   禁用了重定向后，居然显示SSl问题
            //WebClient webClient=webClientBuilder.baseUrl(url).clientConnector(new ReactorClientHttpConnector(httpClient.create().followRedirect(false))).build();
            WebClient webClient=webClientBuilder.baseUrl(url).clientConnector(new ReactorClientHttpConnector(httpClient)).build();

            result= webClient
                    .get()    //发送Get请求
                    //.header(HttpHeaders.ACCEPT, "json/mp3")
                    .retrieve()//检索  自动会重定向
                    .onStatus(HttpStatus::is3xxRedirection, response -> {
                        String location = response.headers().header(HttpHeaders.LOCATION).get(0);
                        System.out.println("重定向的地址为："+location);
                        // 手动处理重定向

                      /*  try {
                            JSONObject result = webClientBuilderGets(location);
                            return Mono.just(result); // 返回 Mono<JSONObject>
                        } catch (Exception e) {
                            return Mono.error(e); // 如果发生错误，返回 Mono<Throwable>
                        }*/
                        RedirectInfo redirectInfo = new RedirectInfo();
                        redirectInfo.setMessage(location);

                        return Mono.error(redirectInfo);
                    })
                    .bodyToMono(String.class)
                    //.log()  //日志打印
                    .block();//阻塞  同步获取结果
            return result;
        }catch (Exception e){
            log.error("随机音乐请求失败:"+e.getMessage());
            RedirectInfo redirectInfo = (RedirectInfo) e.getCause();
            System.out.println( redirectInfo.toString());
            System.out.println(redirectInfo.getMessage());
            result = redirectInfo.getMessage();
        }
        return result;


    }


    //Get请求  同步获取
    public JSONObject webClientGet(String url){
        JSONObject jsonObject= webClient
                .get()    //发送Get请求
                .uri(url)//设置Url
                .retrieve()//检索
                .bodyToMono(JSONObject.class)
                .log()  //日志打印
                .block();//阻塞  同步获取结果
        return jsonObject;
    }


    public JSONObject webClientPost(String url,JSONObject body){
        JSONObject jsonObject=webClient.post()
                .uri(url)
                .body(Mono.just(body),JSONObject.class)//用来创建一个 包含给定值的异步容器，
                .retrieve()
                .bodyToMono(JSONObject.class)
                .block();

        return jsonObject;
    }


    public Mono webClientGetMono(String url){
        Mono<JSONObject> jsonObject= webClient
                .get()    //发送Get请求
                .uri(url)//设置Url
                .retrieve()//检索
                .bodyToMono(JSONObject.class);//异步请求

        //Mono 是异步的，调用 subscribe() 方法表示你愿意处理异步操作的结果。
        // 当数据准备好时，subscribe 中的 Lambda 表达式会被执行。
        jsonObject.subscribe(jsonObject1 -> System.out.println(jsonObject1.toJSONString()));

        return jsonObject;
    }
}
